'''
Created on May 17, 2011

@author: Zhao, Qi
'''

from common import server_log
from common.config import MEMCACHE_POOL
LOG_MEMCACHE_ERROR = True

class Memcache:

    ## default expire time is one day
    def __init__(self, exp_time = 86400, pool = MEMCACHE_POOL):
        self.__expire_time = exp_time
        self.pool = pool
        try:
            with self.pool.reserve() as mc:
                self.memcache = mc
        except Exception,e:
            self.memcache = None
            if LOG_MEMCACHE_ERROR:
                server_log.warning()

    ## key will be converted to a string forcibly
    ## return None when cannot find or any exception
    def get(self, key):
        try:
            if type(key) is not str:
                key = str(key)
            val = self.memcache.get(key)
        except Exception,e:
            if LOG_MEMCACHE_ERROR:
                server_log.warning()
                server_log.warning('The key is ' + key)
            try:
                self.pool.relinquish()
            except Exception:
                pass
            return None
        else:
            return val
        
    def gets(self, key):
        try:
            if type(key) is not str:
                key = str(key)
            val, cas = self.memcache.gets(key)
        except Exception,e:
            if LOG_MEMCACHE_ERROR:
                server_log.warning()
                server_log.warning('The key is ' + key)
            try:
                self.pool.relinquish()
                self.delete(key)
            except Exception:
                pass
            return None, None
        else:
            return val, cas
        
    ## key will be converted to a string forcibly
    ## return False when cannot find or any exception
    def delete(self, key):
        try:
            if type(key) is not str:
                key = str(key)
            val = self.memcache.delete(key)
        except Exception,e:
            if LOG_MEMCACHE_ERROR:
                server_log.warning()
                server_log.warning('The key is ' + key)
            try:
                self.pool.relinquish()
            except Exception:
                pass
            return False
        else:
            return val
    
    ## key will be converted to a string forcibly
    ## return True for success or False for fail
    def set(self, key, value, exp_time = None):
        try:
            if type(key) is not str:
                key = str(key)
            
            expire_time = self.__expire_time if exp_time is None else exp_time
            if expire_time is not None:
                self.memcache.set(key, value, expire_time)
            else:
                self.memcache.set(key, value)
            
        except Exception,e:
            if LOG_MEMCACHE_ERROR:
                server_log.warning()
                server_log.warning('The key is ' + key + ' and value is ' + str(value))
            try:
                self.pool.relinquish()
            except Exception:
                pass
            return False
        else:
            return True
    
    def cas_on_delete(self, key, value, cas, exp_time = None):
        if not self.cas(key, value, cas, exp_time):
            self.delete(key)
            
    def cas(self, key, value, cas, exp_time = None):
        try:
            if type(key) is not str:
                key = str(key)
            
            expire_time = self.__expire_time if exp_time is None else exp_time
            if expire_time is not None:
                result = self.memcache.cas(key, value, cas, expire_time)
            else:
                result = self.memcache.cas(key, value, cas)
            
        except Exception,e:
            if LOG_MEMCACHE_ERROR:
                server_log.warning()
                server_log.warning('The key is ' + key + ' and value is ' + str(value))
            try:
                self.pool.relinquish()
            except Exception:
                pass
            return False
        else:
            return result
    
    
    def incr(self, key):
        try:
            if type(key) is not str:
                key = str(key)            
            new_val = self.memcache.incr(key)
        except Exception,e:
            if LOG_MEMCACHE_ERROR:
                server_log.warning()
                server_log.warning('The key is ' + key)
            try:
                self.pool.relinquish()
            except Exception:
                pass
            return None
        else:
            return new_val

    def decr(self, key):
        try:
            if type(key) is not str:
                key = str(key)            
            new_val = self.memcache.decr(key)
        except Exception,e:
            if LOG_MEMCACHE_ERROR:
                server_log.warning()
                server_log.warning('The key is ' + key)
            try:
                self.pool.relinquish()
            except Exception:
                pass
            return None
        else:
            return new_val
            
    def set_multi(self, kv_pair):
        try:
            if type(kv_pair) is not dict:
                return False     
            self.memcache.set_multi(kv_pair)
        except Exception,e:
            if LOG_MEMCACHE_ERROR:
                server_log.warning()
                server_log.warning('The key pair is ' + str(kv_pair))
            try:
                self.pool.relinquish()
            except Exception:
                pass
            return False
        else:
            return True

    def get_multi(self, key_list):
        try:
            if type(key_list) not in (list, tuple):
                return None
            var_dict = self.memcache.get_multi(key_list)
        except Exception,e:
            if LOG_MEMCACHE_ERROR:
                server_log.warning()
                server_log.warning('The key list is ' + str(key_list))
            try:
                self.pool.relinquish()
            except Exception:
                pass
            return None
        else:
            return var_dict

    def delete_multi(self, key_list):
        try:
            if type(key_list) not in (list, tuple):
                return False
            val = self.memcache.delete_multi(key_list)
        except Exception,e:
            if LOG_MEMCACHE_ERROR:
                server_log.warning()
                server_log.warning('The key list is ' + key_list)
            try:
                self.pool.relinquish()
            except Exception:
                pass
            return False
        else:
            return val